
/* Generated by Interface Builder */

#import "ControlObject.h"
#import "InputView.h"
#import "OutputView.h"
#import "constants.h"
#import "pointdata.h"
#import "proj.h"
#import "fractal.h"
#import <appkit/appkit.h>
#import <math.h>

int started = 0;

float roundToNearestDivisible(float f)
{
	int g,b,l;
	
	if (f<MINROT) {
		f = MINROT;
		return f;
	}
	if (f>MAXROT) {
		f = MAXROT;
		return f;
	}
	
	for(g = round(f);      ((360%g) && (g<=MAXROT));   g++)
	for(l = round(f);    ((360%l) && (l>= MINROT));  l--);
	
	if (l< MINROT)
		l = MINROT;
	if (g> MAXROT)
		g = MAXROT;
		
	if ((fabs(g-round(f))) < fabs((round(f)-l)))
		return (float)g;
	else
		return (float)l;
}

float normalize(float p)
{
	int mult;
	int rem;
	mult = (round(p))/180;
	rem = ((int)(round(p)))%180;
	if (mult%2)
		return (-180 + (p-(180*mult)));
	else
		return  p-(180*mult);
}

@implementation ControlObject

- setIView:anObject
{
    iView = anObject;
    return self;
}

- setGridCell:anObject
{
    gridCell = anObject;
    return self;
}

- setGridCell2:anObject
{
    gridCell2 = anObject;
    return self;
}

- setOView:anObject
{
    oView = anObject;
    return self;
}

- setProjType:anObject
{
    projType = anObject;
    return self;
}

-setElevationfield:anObject
{
    elevationfield = anObject;
    return self;
}
 
- setSlider:anObject
 {
     slider = anObject;
     return self;
 }

- setStep:anObject
{
    step = anObject;
    return self;
}

- setBbplay:anObject
{
	bbplay = anObject;
	return self;
}

- setBplay:anObject
{
	bplay = anObject;
	return self;
}

- setStop:anObject
{
	stop = anObject;
	return self;
}

- setFplay:anObject
{
	fplay = anObject;
	return self;
}

- setFfplay:anObject
{
	ffplay = anObject;
	return self;
}

- setProjectionMatrix:anObject
{
	projectionMatrix = anObject;
	return self;
}

- setScaleField:anObject
{
	scaleField = anObject;
	return self;
}

- setRotationField:anObject
{
	rotationField = anObject;
	return self;
}

- setAlertWindow:anObject
{
	alertWindow = anObject;
	return self;
}

- setAlertText:anObject
{
	alertText = anObject;
	return self;
}

- setHValueField:anObject
{
	hValueField = anObject;
	return self;
}

- setStDevField:anObject
{
	stDevField = anObject;
	return self;
}

- setFractStateButton:anObject
{
	fractStateButton = anObject;
	return self;
}

- setTimeSliceField:anObject
{
	timeSliceField = anObject;
	return self;
}

- setRateSlider:anObject
{
	rateSlider = anObject;
	return self;
}

- setInputMode:anObject
{
	inputMode = anObject;
	return self;
}

- setInputX:anObject
{
	inputX = anObject;
	return self;
}

- setInputY:anObject
{
	inputY = anObject;
	return self;
}

- setInputPen:anObject
{
	inputPen = anObject;
	return self;
}

- saveiView:sender
{
	[iView saveFile];
    return self;
}

- openiView:sender
{
	[iView openFile];
    return self;
}

- newiView:sender
{
	[iView clearFile];
    return self;
}

- gridStateChanged:sender
{
	BOOL oldGridState;
	
	oldGridState = [iView gridState];
	if (oldGridState==YES) {
		[gridCell setTitle:"Set Grid On"];
		[iView setGridState:NO];
	} else {
		[gridCell setTitle:"Set Grid Off"];
		[iView setGridState:YES];
	}
	[[iView window] display];
    return self;
}

- gridStateChanged2:sender
{
	BOOL oldGridState;
	
	oldGridState = [oView gridState];
	if (oldGridState==YES) {
		[gridCell2 setTitle:"Set Grid On"];
		[oView setGridState:NO];
	} else {
		[gridCell2 setTitle:"Set Grid Off"];
		[oView setGridState:YES];
	}
	if (!animation)
		[self refreshOutput];
    return self;
}

- start
{
	float f;

	started = 1;
	[iView setGridState:YES];
	[iView setItUp:self];
	[[iView window] display];
	
	[timeSliceField setFloatValue:[rateSlider floatValue]];
	
	[oView setGridState:YES];
	[oView setItUp:self];
	[oView rateChanged:[timeSliceField floatValue]];
	[[oView window] display];

	force = 1;
	[stop setEnabled:NO];
	pparam.radius = [scaleField floatValue];
	f= [elevationfield floatValue];
	if ((f<(-90.0)) || (f>90.0)) {
		[elevationfield setFloatValue:0.0];
		[slider setFloatValue:0.0];
		pparam.phi1 = 0.0;
	}
	else {
		[slider setFloatValue:f];
		pparam.phi1 = (f/180) * PI;
	}
	f = normalize([rotationField floatValue]);
	[rotationField setFloatValue:f];
	pparam.lon0 = ((f/180) * PI);
	pparam.proj = [[projType selectedCell] tag];
	animation = STOPPED;

	[self getNewInput];
	[self refreshOutput];
	return self;
}

- appDidInit:sender
{
	/* This part gets around the fact that if a document is opened, the "open" program */
	/*	will call appOpenFile before appDidInit.*/
	if (!started)
		[self start];
}
 
- (BOOL)appAcceptsAnotherFile:(id)sender 
{
	return YES;
}

- (int)appOpenFile:(const char *)filename type:(const char *)aType
{
	if (!started)
		[self start];
	[iView openFile:filename];
	return 1;
}

- rotationFieldChanged:sender
{
	float f;
	f = normalize([sender floatValue]);
	[sender setFloatValue:f];
	if (!animation)
		[self refreshOutput];
	return self;
}

- scaleFieldChanged:sender
{
	pparam.radius = [sender floatValue];
	if (!animation)
		[self refreshOutput];
	return self;
}

- elevationfieldchanged:sender
{
	float f;
	
	f= [sender floatValue];
	if ((f<(-90.0)) || (f>90.0)) {
		[sender setFloatValue:[slider floatValue]];
		f = [slider floatValue];
	}
	else {
		[slider setFloatValue:f];
		[sender setFloatValue:f];
		pparam.phi1 = (f/180) * PI;
	}
	if (!animation)
		[self refreshOutput];
	return self;
}

- slidermoved:sender
{
	float f;
	
	f= [sender floatValue];
	[elevationfield setFloatValue:f];
	pparam.phi1 = (f/180) * PI;
	if (!animation)
		[self refreshOutput];
	return self;
}

- stepChanged:sender
{
	float f;
	
	f = [sender floatValue];
	pparam.lon0 = ((f/180)*PI);
	if (!animation)
		[self refreshOutput];
	return self;
}

- projChanged:sender
{
	pparam.proj = [[sender selectedCell] tag];
	if (!animation)
		[self refreshOutput];
	return self;
}

- disableControls
{
	[bbplay setEnabled:NO];
	[bplay setEnabled:NO];
	[stop setEnabled:YES];
	[fplay setEnabled:NO];
	[ffplay setEnabled:NO];
	

	[projType setEnabled:NO];
	[slider setEnabled:NO];
	[elevationfield setEnabled:NO];
	[scaleField setEnabled:NO];
	[rotationField setEnabled:NO];
	[step setEnabled:NO];
	return self;
}

- enableControls
{
	[bbplay setEnabled:YES];
	[bplay setEnabled:YES];
	[stop setEnabled:NO];
	[fplay setEnabled:YES];
	[ffplay setEnabled:YES];

	[projType setEnabled:YES];
	[slider setEnabled:YES];
	[elevationfield setEnabled:YES];
	[scaleField setEnabled:YES];
	[rotationField setEnabled:YES];
	[step setEnabled:YES];
	return self;
}

- bbplayed:sender
{
	float f;
	[stop setEnabled:NO];
	f = [rotationField floatValue];
	[rotationField setFloatValue:(normalize(f+[step floatValue]))];
	[self refreshOutput];
	return self;
}

- bplayed:sender
{
	float f;
	
	[self disableControls];
	f = [step floatValue];
	f = roundToNearestDivisible(f);
	[step setFloatValue:f];

	animation = BACKWARD;
	[self refreshOutput];
	return self;
}

- stopped:sender
{
	[self enableControls];
	animation = STOPPED;
	[self refreshOutput];
	return self;
}

- fplayed:sender
{
	float f;
	
	[self disableControls];
	f = [step floatValue];
	f = roundToNearestDivisible(f);
	[step setFloatValue:f];

	animation = FORWARD;
	[self refreshOutput];
	return self;
}

- ffplayed:sender
{
	float f;
	[stop setEnabled:YES];
	f = [rotationField floatValue];
	[rotationField setFloatValue:(normalize(f-[step floatValue]))];
	[self refreshOutput];
	return self;
}

- getNewInput
{
	PointList *inList;
	
	if (segList.quantity)
		freePointList(&segList);
	newPointList(&segList);
	[iView map:&inList];
	setFValues([fractStateButton state],[hValueField floatValue],[stDevField floatValue]);
	insertFSegments(inList,&segList,&pparam);
	force = 1;
	return self;
}

- refreshOutput
{
	float f;

	pparam.lon0 = (([rotationField floatValue]/180) * PI);
	pparam.phi1 = ([elevationfield floatValue]/180)*PI;
	
	if (animation) {
		[oView setupAnimation:&pparam :[step floatValue] :&segList :force];
		if (force) force = 0;
		[oView startAnimating:animation];
	} else {
		if ([oView animation]) {
			[oView stopAnimating:&f];
			[rotationField setFloatValue:round(normalize(f))];
			pparam.lon0 = (([rotationField floatValue]/180) * PI);
		}
		[oView doStill:&pparam:&segList];
	}
	
	return self;
}

- alertWindow
{
	return alertWindow;
}

- alertText
{
	return alertText;
}

- inputMode
{
	return inputMode;
}

- inputX
{
	return inputX;
}

- inputY
{
	return inputY;
}

- inputPen
{
	return inputPen;
}

- hValueChanged:sender
{
	float f;
	f = [sender floatValue];
	if (f  < 0.0)
		[sender setFloatValue:0.0];
	else if (f > 1.0)
		[sender setFloatValue:1.0];
	[self getNewInput];
	[self refreshOutput];
	return self;
}

- stDevChanged:sender
{
	float f;
	f = [sender floatValue];
	if (f  < 0.0)
		[sender setFloatValue:0.0];
	else if (f > 1.0)
		[sender setFloatValue:1.0];
	[self getNewInput];
	[self refreshOutput];
	return self;
}

- fractalStateChanged:sender
{
	[self getNewInput];
	[self refreshOutput];
	return self;
}

- timeSliceChanged:sender
{
	float f;
	f = [sender floatValue];
	if (f < [rateSlider minValue])
		f = [rateSlider minValue];
	else if (f > 0.5)
		f = [rateSlider maxValue];
	[timeSliceField setFloatValue:f];
	[rateSlider setFloatValue:f];
	[oView rateChanged:f];
	return self;
}

- rateSliderChanged:sender
{
	float f;
	f = [sender floatValue];
	if (f < [rateSlider minValue])
		f = [rateSlider minValue];
	else if (f > [rateSlider maxValue])
		f = [rateSlider maxValue];
	[timeSliceField setFloatValue:f];
	[rateSlider setFloatValue:f];
	[oView rateChanged:f];
	return self;
}

- printOutput:sender
{
	[oView doPrint:&pparam:&segList];
	return self;
}

- mapIt:sender
{
	[self getNewInput];
	[self refreshOutput];
	return self;
}
@end
